001 /* 002 * Copyright 2001-2005 Stephen Colebourne 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 package org.joda.time; 017 018 import java.io.IOException; 019 import java.io.ObjectInputStream; 020 import java.io.ObjectOutputStream; 021 import java.io.Serializable; 022 import java.util.Locale; 023 024 import org.joda.time.base.BaseDateTime; 025 import org.joda.time.chrono.ISOChronology; 026 import org.joda.time.field.AbstractReadableInstantFieldProperty; 027 import org.joda.time.field.FieldUtils; 028 import org.joda.time.format.ISODateTimeFormat; 029 030 /** 031 * MutableDateTime is the standard implementation of a modifiable datetime class. 032 * It holds the datetime as milliseconds from the Java epoch of 1970-01-01T00:00:00Z. 033 * <p> 034 * This class uses a Chronology internally. The Chronology determines how the 035 * millisecond instant value is converted into the date time fields. 036 * The default Chronology is <code>ISOChronology</code> which is the agreed 037 * international standard and compatable with the modern Gregorian calendar. 038 * <p> 039 * Each individual field can be accessed in two ways: 040 * <ul> 041 * <li><code>getHourOfDay()</code> 042 * <li><code>hourOfDay().get()</code> 043 * </ul> 044 * The second technique also provides access to other useful methods on the 045 * field: 046 * <ul> 047 * <li>get numeric value 048 * <li>set numeric value 049 * <li>add to numeric value 050 * <li>add to numeric value wrapping with the field 051 * <li>get text vlaue 052 * <li>get short text value 053 * <li>set text value 054 * <li>field maximum value 055 * <li>field minimum value 056 * </ul> 057 * 058 * <p> 059 * MutableDateTime is mutable and not thread-safe, unless concurrent threads 060 * are not invoking mutator methods. 061 * 062 * @author Guy Allard 063 * @author Brian S O'Neill 064 * @author Stephen Colebourne 065 * @author Mike Schrag 066 * @since 1.0 067 * @see DateTime 068 */ 069 public class MutableDateTime 070 extends BaseDateTime 071 implements ReadWritableDateTime, Cloneable, Serializable { 072 073 /** Serialization version */ 074 private static final long serialVersionUID = 2852608688135209575L; 075 076 /** Rounding is disabled */ 077 public static final int ROUND_NONE = 0; 078 /** Rounding mode as described by {@link DateTimeField#roundFloor} */ 079 public static final int ROUND_FLOOR = 1; 080 /** Rounding mode as described by {@link DateTimeField#roundCeiling} */ 081 public static final int ROUND_CEILING = 2; 082 /** Rounding mode as described by {@link DateTimeField#roundHalfFloor} */ 083 public static final int ROUND_HALF_FLOOR = 3; 084 /** Rounding mode as described by {@link DateTimeField#roundHalfCeiling} */ 085 public static final int ROUND_HALF_CEILING = 4; 086 /** Rounding mode as described by {@link DateTimeField#roundHalfEven} */ 087 public static final int ROUND_HALF_EVEN = 5; 088 089 /** The field to round on */ 090 private DateTimeField iRoundingField; 091 /** The mode of rounding */ 092 private int iRoundingMode; 093 094 //----------------------------------------------------------------------- 095 /** 096 * Constructs an instance set to the current system millisecond time 097 * using <code>ISOChronology</code> in the default time zone. 098 */ 099 public MutableDateTime() { 100 super(); 101 } 102 103 /** 104 * Constructs an instance set to the current system millisecond time 105 * using <code>ISOChronology</code> in the specified time zone. 106 * <p> 107 * If the specified time zone is null, the default zone is used. 108 * 109 * @param zone the time zone, null means default zone 110 */ 111 public MutableDateTime(DateTimeZone zone) { 112 super(zone); 113 } 114 115 /** 116 * Constructs an instance set to the current system millisecond time 117 * using the specified chronology. 118 * <p> 119 * If the chronology is null, <code>ISOChronology</code> 120 * in the default time zone is used. 121 * 122 * @param chronology the chronology, null means ISOChronology in default zone 123 */ 124 public MutableDateTime(Chronology chronology) { 125 super(chronology); 126 } 127 128 //----------------------------------------------------------------------- 129 /** 130 * Constructs an instance set to the milliseconds from 1970-01-01T00:00:00Z 131 * using <code>ISOChronology</code> in the default time zone. 132 * 133 * @param instant the milliseconds from 1970-01-01T00:00:00Z 134 */ 135 public MutableDateTime(long instant) { 136 super(instant); 137 } 138 139 /** 140 * Constructs an instance set to the milliseconds from 1970-01-01T00:00:00Z 141 * using <code>ISOChronology</code> in the specified time zone. 142 * <p> 143 * If the specified time zone is null, the default zone is used. 144 * 145 * @param instant the milliseconds from 1970-01-01T00:00:00Z 146 * @param zone the time zone, null means default zone 147 */ 148 public MutableDateTime(long instant, DateTimeZone zone) { 149 super(instant, zone); 150 } 151 152 /** 153 * Constructs an instance set to the milliseconds from 1970-01-01T00:00:00Z 154 * using the specified chronology. 155 * <p> 156 * If the chronology is null, <code>ISOChronology</code> 157 * in the default time zone is used. 158 * 159 * @param instant the milliseconds from 1970-01-01T00:00:00Z 160 * @param chronology the chronology, null means ISOChronology in default zone 161 */ 162 public MutableDateTime(long instant, Chronology chronology) { 163 super(instant, chronology); 164 } 165 166 //----------------------------------------------------------------------- 167 /** 168 * Constructs an instance from an Object that represents a datetime. 169 * <p> 170 * If the object implies a chronology (such as GregorianCalendar does), 171 * then that chronology will be used. Otherwise, ISO default is used. 172 * Thus if a GregorianCalendar is passed in, the chronology used will 173 * be GJ, but if a Date is passed in the chronology will be ISO. 174 * <p> 175 * The recognised object types are defined in 176 * {@link org.joda.time.convert.ConverterManager ConverterManager} and 177 * include ReadableInstant, String, Calendar and Date. 178 * 179 * @param instant the datetime object, null means now 180 * @throws IllegalArgumentException if the instant is invalid 181 */ 182 public MutableDateTime(Object instant) { 183 super(instant, (Chronology) null); 184 } 185 186 /** 187 * Constructs an instance from an Object that represents a datetime, 188 * forcing the time zone to that specified. 189 * <p> 190 * If the object implies a chronology (such as GregorianCalendar does), 191 * then that chronology will be used, but with the time zone adjusted. 192 * Otherwise, ISO is used in the specified time zone. 193 * If the specified time zone is null, the default zone is used. 194 * Thus if a GregorianCalendar is passed in, the chronology used will 195 * be GJ, but if a Date is passed in the chronology will be ISO. 196 * <p> 197 * The recognised object types are defined in 198 * {@link org.joda.time.convert.ConverterManager ConverterManager} and 199 * include ReadableInstant, String, Calendar and Date. 200 * 201 * @param instant the datetime object, null means now 202 * @param zone the time zone, null means default time zone 203 * @throws IllegalArgumentException if the instant is invalid 204 */ 205 public MutableDateTime(Object instant, DateTimeZone zone) { 206 super(instant, zone); 207 } 208 209 /** 210 * Constructs an instance from an Object that represents a datetime, 211 * using the specified chronology. 212 * <p> 213 * If the chronology is null, ISO in the default time zone is used. 214 * Any chronology implied by the object (such as GregorianCalendar does) 215 * is ignored. 216 * <p> 217 * The recognised object types are defined in 218 * {@link org.joda.time.convert.ConverterManager ConverterManager} and 219 * include ReadableInstant, String, Calendar and Date. 220 * 221 * @param instant the datetime object, null means now 222 * @param chronology the chronology, null means ISOChronology in default zone 223 * @throws IllegalArgumentException if the instant is invalid 224 */ 225 public MutableDateTime(Object instant, Chronology chronology) { 226 super(instant, DateTimeUtils.getChronology(chronology)); 227 } 228 229 //----------------------------------------------------------------------- 230 /** 231 * Constructs an instance from datetime field values 232 * using <code>ISOChronology</code> in the default time zone. 233 * 234 * @param year the year 235 * @param monthOfYear the month of the year 236 * @param dayOfMonth the day of the month 237 * @param hourOfDay the hour of the day 238 * @param minuteOfHour the minute of the hour 239 * @param secondOfMinute the second of the minute 240 * @param millisOfSecond the millisecond of the second 241 */ 242 public MutableDateTime( 243 int year, 244 int monthOfYear, 245 int dayOfMonth, 246 int hourOfDay, 247 int minuteOfHour, 248 int secondOfMinute, 249 int millisOfSecond) { 250 super(year, monthOfYear, dayOfMonth, hourOfDay, minuteOfHour, secondOfMinute, millisOfSecond); 251 } 252 253 /** 254 * Constructs an instance from datetime field values 255 * using <code>ISOChronology</code> in the specified time zone. 256 * <p> 257 * If the specified time zone is null, the default zone is used. 258 * 259 * @param year the year 260 * @param monthOfYear the month of the year 261 * @param dayOfMonth the day of the month 262 * @param hourOfDay the hour of the day 263 * @param minuteOfHour the minute of the hour 264 * @param secondOfMinute the second of the minute 265 * @param millisOfSecond the millisecond of the second 266 * @param zone the time zone, null means default time zone 267 */ 268 public MutableDateTime( 269 int year, 270 int monthOfYear, 271 int dayOfMonth, 272 int hourOfDay, 273 int minuteOfHour, 274 int secondOfMinute, 275 int millisOfSecond, 276 DateTimeZone zone) { 277 super(year, monthOfYear, dayOfMonth, 278 hourOfDay, minuteOfHour, secondOfMinute, millisOfSecond, zone); 279 } 280 281 /** 282 * Constructs an instance from datetime field values 283 * using the specified chronology. 284 * <p> 285 * If the chronology is null, <code>ISOChronology</code> 286 * in the default time zone is used. 287 * 288 * @param year the year 289 * @param monthOfYear the month of the year 290 * @param dayOfMonth the day of the month 291 * @param hourOfDay the hour of the day 292 * @param minuteOfHour the minute of the hour 293 * @param secondOfMinute the second of the minute 294 * @param millisOfSecond the millisecond of the second 295 * @param chronology the chronology, null means ISOChronology in default zone 296 */ 297 public MutableDateTime( 298 int year, 299 int monthOfYear, 300 int dayOfMonth, 301 int hourOfDay, 302 int minuteOfHour, 303 int secondOfMinute, 304 int millisOfSecond, 305 Chronology chronology) { 306 super(year, monthOfYear, dayOfMonth, 307 hourOfDay, minuteOfHour, secondOfMinute, millisOfSecond, chronology); 308 } 309 310 //----------------------------------------------------------------------- 311 /** 312 * Gets the field used for rounding this instant, returning null if rounding 313 * is not enabled. 314 * 315 * @return the rounding field 316 */ 317 public DateTimeField getRoundingField() { 318 return iRoundingField; 319 } 320 321 /** 322 * Gets the rounding mode for this instant, returning ROUND_NONE if rounding 323 * is not enabled. 324 * 325 * @return the rounding mode constant 326 */ 327 public int getRoundingMode() { 328 return iRoundingMode; 329 } 330 331 /** 332 * Sets the status of rounding to use the specified field and ROUND_FLOOR mode. 333 * A null field will disable rounding. 334 * Once set, the instant is then rounded using the new field and mode. 335 * <p> 336 * Enabling rounding will cause all subsequent calls to {@link #setMillis(long)} 337 * to be rounded. This can be used to control the precision of the instant, 338 * for example by setting a rounding field of minuteOfDay, the seconds and 339 * milliseconds will always be zero. 340 * 341 * @param field rounding field or null to disable 342 */ 343 public void setRounding(DateTimeField field) { 344 setRounding(field, MutableDateTime.ROUND_FLOOR); 345 } 346 347 /** 348 * Sets the status of rounding to use the specified field and mode. 349 * A null field or mode of ROUND_NONE will disable rounding. 350 * Once set, the instant is then rounded using the new field and mode. 351 * <p> 352 * Enabling rounding will cause all subsequent calls to {@link #setMillis(long)} 353 * to be rounded. This can be used to control the precision of the instant, 354 * for example by setting a rounding field of minuteOfDay, the seconds and 355 * milliseconds will always be zero. 356 * 357 * @param field rounding field or null to disable 358 * @param mode rounding mode or ROUND_NONE to disable 359 * @throws IllegalArgumentException if mode is unknown, no exception if field is null 360 */ 361 public void setRounding(DateTimeField field, int mode) { 362 if (field != null && (mode < ROUND_NONE || mode > ROUND_HALF_EVEN)) { 363 throw new IllegalArgumentException("Illegal rounding mode: " + mode); 364 } 365 iRoundingField = (mode == ROUND_NONE ? null : field); 366 iRoundingMode = (field == null ? ROUND_NONE : mode); 367 setMillis(getMillis()); 368 } 369 370 //----------------------------------------------------------------------- 371 /** 372 * Set the milliseconds of the datetime. 373 * <p> 374 * All changes to the millisecond field occurs via this method. 375 * 376 * @param instant the milliseconds since 1970-01-01T00:00:00Z to set the 377 * datetime to 378 */ 379 public void setMillis(long instant) { 380 switch (iRoundingMode) { 381 case ROUND_NONE: 382 break; 383 case ROUND_FLOOR: 384 instant = iRoundingField.roundFloor(instant); 385 break; 386 case ROUND_CEILING: 387 instant = iRoundingField.roundCeiling(instant); 388 break; 389 case ROUND_HALF_FLOOR: 390 instant = iRoundingField.roundHalfFloor(instant); 391 break; 392 case ROUND_HALF_CEILING: 393 instant = iRoundingField.roundHalfCeiling(instant); 394 break; 395 case ROUND_HALF_EVEN: 396 instant = iRoundingField.roundHalfEven(instant); 397 break; 398 } 399 400 super.setMillis(instant); 401 } 402 403 /** 404 * Sets the millisecond instant of this instant from another. 405 * <p> 406 * This method does not change the chronology of this instant, just the 407 * millisecond instant. 408 * 409 * @param instant the instant to use, null means now 410 */ 411 public void setMillis(ReadableInstant instant) { 412 long instantMillis = DateTimeUtils.getInstantMillis(instant); 413 setMillis(instantMillis); // set via this class not super 414 } 415 416 //----------------------------------------------------------------------- 417 /** 418 * Add an amount of time to the datetime. 419 * 420 * @param duration the millis to add 421 * @throws ArithmeticException if the result exceeds the capacity of the instant 422 */ 423 public void add(long duration) { 424 setMillis(FieldUtils.safeAdd(getMillis(), duration)); // set via this class not super 425 } 426 427 /** 428 * Adds a duration to this instant. 429 * <p> 430 * This will typically change the value of most fields. 431 * 432 * @param duration the duration to add, null means add zero 433 * @throws ArithmeticException if the result exceeds the capacity of the instant 434 */ 435 public void add(ReadableDuration duration) { 436 add(duration, 1); 437 } 438 439 /** 440 * Adds a duration to this instant specifying how many times to add. 441 * <p> 442 * This will typically change the value of most fields. 443 * 444 * @param duration the duration to add, null means add zero 445 * @param scalar direction and amount to add, which may be negative 446 * @throws ArithmeticException if the result exceeds the capacity of the instant 447 */ 448 public void add(ReadableDuration duration, int scalar) { 449 if (duration != null) { 450 add(FieldUtils.safeMultiply(duration.getMillis(), scalar)); 451 } 452 } 453 454 /** 455 * Adds a period to this instant. 456 * <p> 457 * This will typically change the value of most fields. 458 * 459 * @param period the period to add, null means add zero 460 * @throws ArithmeticException if the result exceeds the capacity of the instant 461 */ 462 public void add(ReadablePeriod period) { 463 add(period, 1); 464 } 465 466 /** 467 * Adds a period to this instant specifying how many times to add. 468 * <p> 469 * This will typically change the value of most fields. 470 * 471 * @param period the period to add, null means add zero 472 * @param scalar direction and amount to add, which may be negative 473 * @throws ArithmeticException if the result exceeds the capacity of the instant 474 */ 475 public void add(ReadablePeriod period, int scalar) { 476 if (period != null) { 477 setMillis(getChronology().add(period, getMillis(), scalar)); // set via this class not super 478 } 479 } 480 481 //----------------------------------------------------------------------- 482 /** 483 * Set the chronology of the datetime. 484 * <p> 485 * All changes to the chronology occur via this method. 486 * 487 * @param chronology the chronology to use, null means ISOChronology in default zone 488 */ 489 public void setChronology(Chronology chronology) { 490 super.setChronology(chronology); 491 } 492 493 //----------------------------------------------------------------------- 494 /** 495 * Sets the time zone of the datetime, changing the chronology and field values. 496 * <p> 497 * Changing the zone using this method retains the millisecond instant. 498 * The millisecond instant is adjusted in the new zone to compensate. 499 * 500 * chronology. Setting the time zone does not affect the millisecond value 501 * of this instant. 502 * <p> 503 * If the chronology already has this time zone, no change occurs. 504 * 505 * @param newZone the time zone to use, null means default zone 506 * @see #setZoneRetainFields 507 */ 508 public void setZone(DateTimeZone newZone) { 509 newZone = DateTimeUtils.getZone(newZone); 510 Chronology chrono = getChronology(); 511 if (chrono.getZone() != newZone) { 512 setChronology(chrono.withZone(newZone)); // set via this class not super 513 } 514 } 515 516 /** 517 * Sets the time zone of the datetime, changing the chronology and millisecond. 518 * <p> 519 * Changing the zone using this method retains the field values. 520 * The millisecond instant is adjusted in the new zone to compensate. 521 * <p> 522 * If the chronology already has this time zone, no change occurs. 523 * 524 * @param newZone the time zone to use, null means default zone 525 * @see #setZone 526 */ 527 public void setZoneRetainFields(DateTimeZone newZone) { 528 newZone = DateTimeUtils.getZone(newZone); 529 DateTimeZone originalZone = DateTimeUtils.getZone(getZone()); 530 if (newZone == originalZone) { 531 return; 532 } 533 534 long millis = originalZone.getMillisKeepLocal(newZone, getMillis()); 535 setChronology(getChronology().withZone(newZone)); // set via this class not super 536 setMillis(millis); 537 } 538 539 //----------------------------------------------------------------------- 540 /** 541 * Sets the value of one of the fields of the instant, such as hourOfDay. 542 * 543 * @param type a field type, usually obtained from DateTimeFieldType, not null 544 * @param value the value to set the field to 545 * @throws IllegalArgumentException if the value is null or invalid 546 */ 547 public void set(DateTimeFieldType type, int value) { 548 if (type == null) { 549 throw new IllegalArgumentException("Field must not be null"); 550 } 551 setMillis(type.getField(getChronology()).set(getMillis(), value)); 552 } 553 554 /** 555 * Adds to the instant specifying the duration and multiple to add. 556 * 557 * @param type a field type, usually obtained from DateTimeFieldType, not null 558 * @param amount the amount to add of this duration 559 * @throws IllegalArgumentException if the value is null or invalid 560 * @throws ArithmeticException if the result exceeds the capacity of the instant 561 */ 562 public void add(DurationFieldType type, int amount) { 563 if (type == null) { 564 throw new IllegalArgumentException("Field must not be null"); 565 } 566 setMillis(type.getField(getChronology()).add(getMillis(), amount)); 567 } 568 569 //----------------------------------------------------------------------- 570 /** 571 * Set the year to the specified value. 572 * 573 * @param year the year 574 * @throws IllegalArgumentException if the value is invalid 575 */ 576 public void setYear(final int year) { 577 setMillis(getChronology().year().set(getMillis(), year)); 578 } 579 580 /** 581 * Add a number of years to the date. 582 * 583 * @param years the years to add 584 * @throws IllegalArgumentException if the value is invalid 585 */ 586 public void addYears(final int years) { 587 setMillis(getChronology().years().add(getMillis(), years)); 588 } 589 590 //----------------------------------------------------------------------- 591 /** 592 * Set the weekyear to the specified value. 593 * 594 * @param weekyear the weekyear 595 * @throws IllegalArgumentException if the value is invalid 596 */ 597 public void setWeekyear(final int weekyear) { 598 setMillis(getChronology().weekyear().set(getMillis(), weekyear)); 599 } 600 601 /** 602 * Add a number of weekyears to the date. 603 * 604 * @param weekyears the weekyears to add 605 * @throws IllegalArgumentException if the value is invalid 606 */ 607 public void addWeekyears(final int weekyears) { 608 setMillis(getChronology().weekyears().add(getMillis(), weekyears)); 609 } 610 611 //----------------------------------------------------------------------- 612 /** 613 * Set the month of the year to the specified value. 614 * 615 * @param monthOfYear the month of the year 616 * @throws IllegalArgumentException if the value is invalid 617 */ 618 public void setMonthOfYear(final int monthOfYear) { 619 setMillis(getChronology().monthOfYear().set(getMillis(), monthOfYear)); 620 } 621 622 /** 623 * Add a number of months to the date. 624 * 625 * @param months the months to add 626 * @throws IllegalArgumentException if the value is invalid 627 */ 628 public void addMonths(final int months) { 629 setMillis(getChronology().months().add(getMillis(), months)); 630 } 631 632 //----------------------------------------------------------------------- 633 /** 634 * Set the week of weekyear to the specified value. 635 * 636 * @param weekOfWeekyear the week of the weekyear 637 * @throws IllegalArgumentException if the value is invalid 638 */ 639 public void setWeekOfWeekyear(final int weekOfWeekyear) { 640 setMillis(getChronology().weekOfWeekyear().set(getMillis(), weekOfWeekyear)); 641 } 642 643 /** 644 * Add a number of weeks to the date. 645 * 646 * @param weeks the weeks to add 647 * @throws IllegalArgumentException if the value is invalid 648 */ 649 public void addWeeks(final int weeks) { 650 setMillis(getChronology().weeks().add(getMillis(), weeks)); 651 } 652 653 //----------------------------------------------------------------------- 654 /** 655 * Set the day of year to the specified value. 656 * 657 * @param dayOfYear the day of the year 658 * @throws IllegalArgumentException if the value is invalid 659 */ 660 public void setDayOfYear(final int dayOfYear) { 661 setMillis(getChronology().dayOfYear().set(getMillis(), dayOfYear)); 662 } 663 664 /** 665 * Set the day of the month to the specified value. 666 * 667 * @param dayOfMonth the day of the month 668 * @throws IllegalArgumentException if the value is invalid 669 */ 670 public void setDayOfMonth(final int dayOfMonth) { 671 setMillis(getChronology().dayOfMonth().set(getMillis(), dayOfMonth)); 672 } 673 674 /** 675 * Set the day of week to the specified value. 676 * 677 * @param dayOfWeek the day of the week 678 * @throws IllegalArgumentException if the value is invalid 679 */ 680 public void setDayOfWeek(final int dayOfWeek) { 681 setMillis(getChronology().dayOfWeek().set(getMillis(), dayOfWeek)); 682 } 683 684 /** 685 * Add a number of days to the date. 686 * 687 * @param days the days to add 688 * @throws IllegalArgumentException if the value is invalid 689 */ 690 public void addDays(final int days) { 691 setMillis(getChronology().days().add(getMillis(), days)); 692 } 693 694 //----------------------------------------------------------------------- 695 /** 696 * Set the hour of the day to the specified value. 697 * 698 * @param hourOfDay the hour of day 699 * @throws IllegalArgumentException if the value is invalid 700 */ 701 public void setHourOfDay(final int hourOfDay) { 702 setMillis(getChronology().hourOfDay().set(getMillis(), hourOfDay)); 703 } 704 705 /** 706 * Add a number of hours to the date. 707 * 708 * @param hours the hours to add 709 * @throws IllegalArgumentException if the value is invalid 710 */ 711 public void addHours(final int hours) { 712 setMillis(getChronology().hours().add(getMillis(), hours)); 713 } 714 715 //----------------------------------------------------------------------- 716 /** 717 * Set the minute of the day to the specified value. 718 * 719 * @param minuteOfDay the minute of day 720 * @throws IllegalArgumentException if the value is invalid 721 */ 722 public void setMinuteOfDay(final int minuteOfDay) { 723 setMillis(getChronology().minuteOfDay().set(getMillis(), minuteOfDay)); 724 } 725 726 /** 727 * Set the minute of the hour to the specified value. 728 * 729 * @param minuteOfHour the minute of hour 730 * @throws IllegalArgumentException if the value is invalid 731 */ 732 public void setMinuteOfHour(final int minuteOfHour) { 733 setMillis(getChronology().minuteOfHour().set(getMillis(), minuteOfHour)); 734 } 735 736 /** 737 * Add a number of minutes to the date. 738 * 739 * @param minutes the minutes to add 740 * @throws IllegalArgumentException if the value is invalid 741 */ 742 public void addMinutes(final int minutes) { 743 setMillis(getChronology().minutes().add(getMillis(), minutes)); 744 } 745 746 //----------------------------------------------------------------------- 747 /** 748 * Set the second of the day to the specified value. 749 * 750 * @param secondOfDay the second of day 751 * @throws IllegalArgumentException if the value is invalid 752 */ 753 public void setSecondOfDay(final int secondOfDay) { 754 setMillis(getChronology().secondOfDay().set(getMillis(), secondOfDay)); 755 } 756 757 /** 758 * Set the second of the minute to the specified value. 759 * 760 * @param secondOfMinute the second of minute 761 * @throws IllegalArgumentException if the value is invalid 762 */ 763 public void setSecondOfMinute(final int secondOfMinute) { 764 setMillis(getChronology().secondOfMinute().set(getMillis(), secondOfMinute)); 765 } 766 767 /** 768 * Add a number of seconds to the date. 769 * 770 * @param seconds the seconds to add 771 * @throws IllegalArgumentException if the value is invalid 772 */ 773 public void addSeconds(final int seconds) { 774 setMillis(getChronology().seconds().add(getMillis(), seconds)); 775 } 776 777 //----------------------------------------------------------------------- 778 /** 779 * Set the millis of the day to the specified value. 780 * 781 * @param millisOfDay the millis of day 782 * @throws IllegalArgumentException if the value is invalid 783 */ 784 public void setMillisOfDay(final int millisOfDay) { 785 setMillis(getChronology().millisOfDay().set(getMillis(), millisOfDay)); 786 } 787 788 /** 789 * Set the millis of the second to the specified value. 790 * 791 * @param millisOfSecond the millis of second 792 * @throws IllegalArgumentException if the value is invalid 793 */ 794 public void setMillisOfSecond(final int millisOfSecond) { 795 setMillis(getChronology().millisOfSecond().set(getMillis(), millisOfSecond)); 796 } 797 798 /** 799 * Add a number of milliseconds to the date. The implementation of this 800 * method differs from the {@link #add(long)} method in that a 801 * DateTimeField performs the addition. 802 * 803 * @param millis the milliseconds to add 804 * @throws IllegalArgumentException if the value is invalid 805 */ 806 public void addMillis(final int millis) { 807 setMillis(getChronology().millis().add(getMillis(), millis)); 808 } 809 810 //----------------------------------------------------------------------- 811 /** 812 * Set the date from milliseconds. 813 * The time part of this object will be unaffected. 814 * 815 * @param instant an instant to copy the date from, time part ignored 816 * @throws IllegalArgumentException if the value is invalid 817 */ 818 public void setDate(final long instant) { 819 setMillis(getChronology().millisOfDay().set(instant, getMillisOfDay())); 820 } 821 822 /** 823 * Set the date from another instant. 824 * The time part of this object will be unaffected. 825 * 826 * @param instant an instant to copy the date from, time part ignored 827 * @throws IllegalArgumentException if the object is invalid 828 */ 829 public void setDate(final ReadableInstant instant) { 830 long instantMillis = DateTimeUtils.getInstantMillis(instant); 831 Chronology instantChrono = DateTimeUtils.getInstantChronology(instant); 832 DateTimeZone zone = instantChrono.getZone(); 833 if (zone != null) { 834 instantMillis = zone.getMillisKeepLocal(DateTimeZone.UTC, instantMillis); 835 } 836 setDate(instantMillis); 837 } 838 839 /** 840 * Set the date from fields. 841 * The time part of this object will be unaffected. 842 * 843 * @param year the year 844 * @param monthOfYear the month of the year 845 * @param dayOfMonth the day of the month 846 * @throws IllegalArgumentException if the value is invalid 847 */ 848 public void setDate( 849 final int year, 850 final int monthOfYear, 851 final int dayOfMonth) { 852 Chronology c = getChronology(); 853 long instantMidnight = c.getDateTimeMillis(year, monthOfYear, dayOfMonth, 0); 854 setDate(instantMidnight); 855 } 856 857 //----------------------------------------------------------------------- 858 /** 859 * Set the time from milliseconds. 860 * The date part of this object will be unaffected. 861 * 862 * @param millis an instant to copy the time from, date part ignored 863 * @throws IllegalArgumentException if the value is invalid 864 */ 865 public void setTime(final long millis) { 866 int millisOfDay = ISOChronology.getInstanceUTC().millisOfDay().get(millis); 867 setMillis(getChronology().millisOfDay().set(getMillis(), millisOfDay)); 868 } 869 870 /** 871 * Set the time from another instant. 872 * The date part of this object will be unaffected. 873 * 874 * @param instant an instant to copy the time from, date part ignored 875 * @throws IllegalArgumentException if the object is invalid 876 */ 877 public void setTime(final ReadableInstant instant) { 878 long instantMillis = DateTimeUtils.getInstantMillis(instant); 879 Chronology instantChrono = DateTimeUtils.getInstantChronology(instant); 880 DateTimeZone zone = instantChrono.getZone(); 881 if (zone != null) { 882 instantMillis = zone.getMillisKeepLocal(DateTimeZone.UTC, instantMillis); 883 } 884 setTime(instantMillis); 885 } 886 887 /** 888 * Set the time from fields. 889 * The date part of this object will be unaffected. 890 * 891 * @param hour the hour 892 * @param minuteOfHour the minute of the hour 893 * @param secondOfMinute the second of the minute 894 * @param millisOfSecond the millisecond of the second 895 * @throws IllegalArgumentException if the value is invalid 896 */ 897 public void setTime( 898 final int hour, 899 final int minuteOfHour, 900 final int secondOfMinute, 901 final int millisOfSecond) { 902 long instant = getChronology().getDateTimeMillis( 903 getMillis(), hour, minuteOfHour, secondOfMinute, millisOfSecond); 904 setMillis(instant); 905 } 906 907 /** 908 * Set the date and time from fields. 909 * 910 * @param year the year 911 * @param monthOfYear the month of the year 912 * @param dayOfMonth the day of the month 913 * @param hourOfDay the hour of the day 914 * @param minuteOfHour the minute of the hour 915 * @param secondOfMinute the second of the minute 916 * @param millisOfSecond the millisecond of the second 917 * @throws IllegalArgumentException if the value is invalid 918 */ 919 public void setDateTime( 920 final int year, 921 final int monthOfYear, 922 final int dayOfMonth, 923 final int hourOfDay, 924 final int minuteOfHour, 925 final int secondOfMinute, 926 final int millisOfSecond) { 927 long instant = getChronology().getDateTimeMillis( 928 year, monthOfYear, dayOfMonth, hourOfDay, minuteOfHour, secondOfMinute, millisOfSecond); 929 setMillis(instant); 930 } 931 932 //----------------------------------------------------------------------- 933 /** 934 * Gets the property object for the specified type, which contains many useful methods. 935 * 936 * @param type the field type to get the chronology for 937 * @return the property object 938 * @throws IllegalArgumentException if the field is null or unsupported 939 * @since 1.2 940 */ 941 public Property property(DateTimeFieldType type) { 942 if (type == null) { 943 throw new IllegalArgumentException("The DateTimeFieldType must not be null"); 944 } 945 DateTimeField field = type.getField(getChronology()); 946 if (field.isSupported() == false) { 947 throw new IllegalArgumentException("Field '" + type + "' is not supported"); 948 } 949 return new Property(this, field); 950 } 951 952 /** 953 * Get the era property. 954 * 955 * @return the era property 956 */ 957 public Property era() { 958 return new Property(this, getChronology().era()); 959 } 960 961 /** 962 * Get the century of era property. 963 * 964 * @return the year of era property 965 */ 966 public Property centuryOfEra() { 967 return new Property(this, getChronology().centuryOfEra()); 968 } 969 970 /** 971 * Get the year of century property. 972 * 973 * @return the year of era property 974 */ 975 public Property yearOfCentury() { 976 return new Property(this, getChronology().yearOfCentury()); 977 } 978 979 /** 980 * Get the year of era property. 981 * 982 * @return the year of era property 983 */ 984 public Property yearOfEra() { 985 return new Property(this, getChronology().yearOfEra()); 986 } 987 988 /** 989 * Get the year property. 990 * 991 * @return the year property 992 */ 993 public Property year() { 994 return new Property(this, getChronology().year()); 995 } 996 997 /** 998 * Get the year of a week based year property. 999 * 1000 * @return the year of a week based year property 1001 */ 1002 public Property weekyear() { 1003 return new Property(this, getChronology().weekyear()); 1004 } 1005 1006 /** 1007 * Get the month of year property. 1008 * 1009 * @return the month of year property 1010 */ 1011 public Property monthOfYear() { 1012 return new Property(this, getChronology().monthOfYear()); 1013 } 1014 1015 /** 1016 * Get the week of a week based year property. 1017 * 1018 * @return the week of a week based year property 1019 */ 1020 public Property weekOfWeekyear() { 1021 return new Property(this, getChronology().weekOfWeekyear()); 1022 } 1023 1024 /** 1025 * Get the day of year property. 1026 * 1027 * @return the day of year property 1028 */ 1029 public Property dayOfYear() { 1030 return new Property(this, getChronology().dayOfYear()); 1031 } 1032 1033 /** 1034 * Get the day of month property. 1035 * <p> 1036 * The values for day of month are defined in {@link DateTimeConstants}. 1037 * 1038 * @return the day of month property 1039 */ 1040 public Property dayOfMonth() { 1041 return new Property(this, getChronology().dayOfMonth()); 1042 } 1043 1044 /** 1045 * Get the day of week property. 1046 * <p> 1047 * The values for day of week are defined in {@link DateTimeConstants}. 1048 * 1049 * @return the day of week property 1050 */ 1051 public Property dayOfWeek() { 1052 return new Property(this, getChronology().dayOfWeek()); 1053 } 1054 1055 //----------------------------------------------------------------------- 1056 /** 1057 * Get the hour of day field property 1058 * 1059 * @return the hour of day property 1060 */ 1061 public Property hourOfDay() { 1062 return new Property(this, getChronology().hourOfDay()); 1063 } 1064 1065 /** 1066 * Get the minute of day property 1067 * 1068 * @return the minute of day property 1069 */ 1070 public Property minuteOfDay() { 1071 return new Property(this, getChronology().minuteOfDay()); 1072 } 1073 1074 /** 1075 * Get the minute of hour field property 1076 * 1077 * @return the minute of hour property 1078 */ 1079 public Property minuteOfHour() { 1080 return new Property(this, getChronology().minuteOfHour()); 1081 } 1082 1083 /** 1084 * Get the second of day property 1085 * 1086 * @return the second of day property 1087 */ 1088 public Property secondOfDay() { 1089 return new Property(this, getChronology().secondOfDay()); 1090 } 1091 1092 /** 1093 * Get the second of minute field property 1094 * 1095 * @return the second of minute property 1096 */ 1097 public Property secondOfMinute() { 1098 return new Property(this, getChronology().secondOfMinute()); 1099 } 1100 1101 /** 1102 * Get the millis of day property 1103 * 1104 * @return the millis of day property 1105 */ 1106 public Property millisOfDay() { 1107 return new Property(this, getChronology().millisOfDay()); 1108 } 1109 1110 /** 1111 * Get the millis of second property 1112 * 1113 * @return the millis of second property 1114 */ 1115 public Property millisOfSecond() { 1116 return new Property(this, getChronology().millisOfSecond()); 1117 } 1118 1119 //----------------------------------------------------------------------- 1120 /** 1121 * Clone this object without having to cast the returned object. 1122 * 1123 * @return a clone of the this object. 1124 */ 1125 public MutableDateTime copy() { 1126 return (MutableDateTime) clone(); 1127 } 1128 1129 //----------------------------------------------------------------------- 1130 /** 1131 * Clone this object. 1132 * 1133 * @return a clone of this object. 1134 */ 1135 public Object clone() { 1136 try { 1137 return super.clone(); 1138 } catch (CloneNotSupportedException ex) { 1139 throw new InternalError("Clone error"); 1140 } 1141 } 1142 1143 /** 1144 * Output the date time in ISO8601 format (yyyy-MM-ddTHH:mm:ss.SSSZZ). 1145 * 1146 * @return ISO8601 time formatted string. 1147 */ 1148 public String toString() { 1149 return ISODateTimeFormat.dateTime().print(this); 1150 } 1151 1152 /** 1153 * MutableDateTime.Property binds a MutableDateTime to a 1154 * DateTimeField allowing powerful datetime functionality to be easily 1155 * accessed. 1156 * <p> 1157 * The example below shows how to use the property to change the value of a 1158 * MutableDateTime object. 1159 * <pre> 1160 * MutableDateTime dt = new MutableDateTime(1972, 12, 3, 13, 32, 19, 123); 1161 * dt.year().add(20); 1162 * dt.second().roundFloor().minute().set(10); 1163 * </pre> 1164 * <p> 1165 * MutableDateTime.Propery itself is thread-safe and immutable, but the 1166 * MutableDateTime being operated on is not. 1167 * 1168 * @author Stephen Colebourne 1169 * @author Brian S O'Neill 1170 * @since 1.0 1171 */ 1172 public static final class Property extends AbstractReadableInstantFieldProperty { 1173 1174 /** Serialization version */ 1175 private static final long serialVersionUID = -4481126543819298617L; 1176 1177 /** The instant this property is working against */ 1178 private MutableDateTime iInstant; 1179 /** The field this property is working against */ 1180 private DateTimeField iField; 1181 1182 /** 1183 * Constructor. 1184 * 1185 * @param instant the instant to set 1186 * @param field the field to use 1187 */ 1188 Property(MutableDateTime instant, DateTimeField field) { 1189 super(); 1190 iInstant = instant; 1191 iField = field; 1192 } 1193 1194 /** 1195 * Writes the property in a safe serialization format. 1196 */ 1197 private void writeObject(ObjectOutputStream oos) throws IOException { 1198 oos.writeObject(iInstant); 1199 oos.writeObject(iField.getType()); 1200 } 1201 1202 /** 1203 * Reads the property from a safe serialization format. 1204 */ 1205 private void readObject(ObjectInputStream oos) throws IOException, ClassNotFoundException { 1206 iInstant = (MutableDateTime) oos.readObject(); 1207 DateTimeFieldType type = (DateTimeFieldType) oos.readObject(); 1208 iField = type.getField(iInstant.getChronology()); 1209 } 1210 1211 //----------------------------------------------------------------------- 1212 /** 1213 * Gets the field being used. 1214 * 1215 * @return the field 1216 */ 1217 public DateTimeField getField() { 1218 return iField; 1219 } 1220 1221 /** 1222 * Gets the milliseconds of the datetime that this property is linked to. 1223 * 1224 * @return the milliseconds 1225 */ 1226 protected long getMillis() { 1227 return iInstant.getMillis(); 1228 } 1229 1230 /** 1231 * Gets the chronology of the datetime that this property is linked to. 1232 * 1233 * @return the chronology 1234 * @since 1.4 1235 */ 1236 protected Chronology getChronology() { 1237 return iInstant.getChronology(); 1238 } 1239 1240 /** 1241 * Gets the mutable datetime being used. 1242 * 1243 * @return the mutable datetime 1244 */ 1245 public MutableDateTime getMutableDateTime() { 1246 return iInstant; 1247 } 1248 1249 //----------------------------------------------------------------------- 1250 /** 1251 * Adds a value to the millis value. 1252 * 1253 * @param value the value to add 1254 * @return the mutable datetime being used, so calls can be chained 1255 * @see DateTimeField#add(long,int) 1256 */ 1257 public MutableDateTime add(int value) { 1258 iInstant.setMillis(getField().add(iInstant.getMillis(), value)); 1259 return iInstant; 1260 } 1261 1262 /** 1263 * Adds a value to the millis value. 1264 * 1265 * @param value the value to add 1266 * @return the mutable datetime being used, so calls can be chained 1267 * @see DateTimeField#add(long,long) 1268 */ 1269 public MutableDateTime add(long value) { 1270 iInstant.setMillis(getField().add(iInstant.getMillis(), value)); 1271 return iInstant; 1272 } 1273 1274 /** 1275 * Adds a value, possibly wrapped, to the millis value. 1276 * 1277 * @param value the value to add 1278 * @return the mutable datetime being used, so calls can be chained 1279 * @see DateTimeField#addWrapField 1280 */ 1281 public MutableDateTime addWrapField(int value) { 1282 iInstant.setMillis(getField().addWrapField(iInstant.getMillis(), value)); 1283 return iInstant; 1284 } 1285 1286 //----------------------------------------------------------------------- 1287 /** 1288 * Sets a value. 1289 * 1290 * @param value the value to set. 1291 * @return the mutable datetime being used, so calls can be chained 1292 * @see DateTimeField#set(long,int) 1293 */ 1294 public MutableDateTime set(int value) { 1295 iInstant.setMillis(getField().set(iInstant.getMillis(), value)); 1296 return iInstant; 1297 } 1298 1299 /** 1300 * Sets a text value. 1301 * 1302 * @param text the text value to set 1303 * @param locale optional locale to use for selecting a text symbol 1304 * @return the mutable datetime being used, so calls can be chained 1305 * @throws IllegalArgumentException if the text value isn't valid 1306 * @see DateTimeField#set(long,java.lang.String,java.util.Locale) 1307 */ 1308 public MutableDateTime set(String text, Locale locale) { 1309 iInstant.setMillis(getField().set(iInstant.getMillis(), text, locale)); 1310 return iInstant; 1311 } 1312 1313 /** 1314 * Sets a text value. 1315 * 1316 * @param text the text value to set 1317 * @return the mutable datetime being used, so calls can be chained 1318 * @throws IllegalArgumentException if the text value isn't valid 1319 * @see DateTimeField#set(long,java.lang.String) 1320 */ 1321 public MutableDateTime set(String text) { 1322 set(text, null); 1323 return iInstant; 1324 } 1325 1326 //----------------------------------------------------------------------- 1327 /** 1328 * Round to the lowest whole unit of this field. 1329 * 1330 * @return the mutable datetime being used, so calls can be chained 1331 * @see DateTimeField#roundFloor 1332 */ 1333 public MutableDateTime roundFloor() { 1334 iInstant.setMillis(getField().roundFloor(iInstant.getMillis())); 1335 return iInstant; 1336 } 1337 1338 /** 1339 * Round to the highest whole unit of this field. 1340 * 1341 * @return the mutable datetime being used, so calls can be chained 1342 * @see DateTimeField#roundCeiling 1343 */ 1344 public MutableDateTime roundCeiling() { 1345 iInstant.setMillis(getField().roundCeiling(iInstant.getMillis())); 1346 return iInstant; 1347 } 1348 1349 /** 1350 * Round to the nearest whole unit of this field, favoring the floor if 1351 * halfway. 1352 * 1353 * @return the mutable datetime being used, so calls can be chained 1354 * @see DateTimeField#roundHalfFloor 1355 */ 1356 public MutableDateTime roundHalfFloor() { 1357 iInstant.setMillis(getField().roundHalfFloor(iInstant.getMillis())); 1358 return iInstant; 1359 } 1360 1361 /** 1362 * Round to the nearest whole unit of this field, favoring the ceiling if 1363 * halfway. 1364 * 1365 * @return the mutable datetime being used, so calls can be chained 1366 * @see DateTimeField#roundHalfCeiling 1367 */ 1368 public MutableDateTime roundHalfCeiling() { 1369 iInstant.setMillis(getField().roundHalfCeiling(iInstant.getMillis())); 1370 return iInstant; 1371 } 1372 1373 /** 1374 * Round to the nearest whole unit of this field. If halfway, the ceiling 1375 * is favored over the floor only if it makes this field's value even. 1376 * 1377 * @return the mutable datetime being used, so calls can be chained 1378 * @see DateTimeField#roundHalfEven 1379 */ 1380 public MutableDateTime roundHalfEven() { 1381 iInstant.setMillis(getField().roundHalfEven(iInstant.getMillis())); 1382 return iInstant; 1383 } 1384 } 1385 1386 }